#pragma once
#include<iostream>
#include<pthread.h>
#include<unistd.h>
#include<queue>
#include<stdlib.h>

using namespace std;

#define CAP 5

template<class T>
class cp_blockqueue
{
private:
    queue<T> bq_; //我们的阻塞队列
    int cap_;   //队列的元素上限
    pthread_mutex_t mtx_;   //保护临界资源的锁
    
    //1. 当生产满了的时候，就应该不要生产了(不要竞争锁了)，而应该让消费者来消费
    //2. 当消费空了，就不应该消费（不要竞争锁了）,应该让生产者来进行生产
    pthread_cond_t is_full_; //bq_满的， 消费者等待该条件变量
    pthread_cond_t is_empty_; //bq_空的，生产者等待该条件变量

public:
    //const &:输入
    //*: 输出
    //&: 输入输出
    void push(const T& data)//生产者向队列里输入数据
    {
        pthread_mutex_lock(&mtx_);
        if(bq_.size() == cap_)//如果队列是满的，就要等待消费者消费
        {
            pthread_cond_wait(&is_empty_, &mtx_);
        }

        bq_.push(data);

        //if(bq_.size() > cap_/2)
            pthread_cond_signal(&is_full_);//唤醒消费者，告诉他生产数量够了

        pthread_mutex_unlock(&mtx_);
    }

    void pop(T*const data)//消费者从队列里取出数据
    {
        pthread_mutex_lock(&mtx_);
        if(bq_.size() == 0)//如果队列是空的，就要等待生产者生产
        {
            pthread_cond_wait(&is_full_, &mtx_);
        }

        *data = bq_.front();
        bq_.pop();
        //if(bq_.size() < cap_/2)
            pthread_cond_signal(&is_empty_);//唤醒生产者，告诉他可以生产了
        pthread_mutex_unlock(&mtx_);
    }

public:
    cp_blockqueue(int cap = CAP)
    {
        cap_ = cap;
        pthread_mutex_init(&mtx_, nullptr);
        pthread_cond_init(&is_full_, nullptr);
        pthread_cond_init(&is_empty_, nullptr);
    }

    ~cp_blockqueue()
    {
        pthread_mutex_destroy(&mtx_);
        pthread_cond_destroy(&is_full_);
        pthread_cond_destroy(&is_empty_);
    }
};